package com.sdms.controller;

import com.sdms.common.result.LayuiResult;
import com.sdms.common.util.MD5Utils;
import com.sdms.config.PictureConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static com.sdms.common.util.StringUtils.isBlankOrNull;
import static com.sdms.common.util.StringUtils.isEmpty;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;

@SuppressWarnings("unused")
@Tag(name = "图片文件上传api")
@Controller
public class PictureUploadController {
    private static final Logger log = LoggerFactory.getLogger(PictureUploadController.class);

    private static final byte[] PNG = {(byte) 0x89, (byte) 0x50, (byte) 0x4E, (byte) 0x47};

    private static final byte[] JPG = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};

    private static final byte[] GIF = {(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38};

    @Resource
    private PictureConfig pictureConfig;

    /**
     * 本地图片文件上传接口 "/upload"
     *
     * @param file 上传的图片文件, 参数名是 file, (例如：用原生form提交,input标签需要添加 name="file" )
     * @return JSON格式的对象, code == 0 表示上传成功 , code == 1 表示上传失败
     */
    @Operation(summary = "ajax:本地图片文件上传")
    @PostMapping("/upload")
    @ResponseBody
    public LayuiResult<Object> upload(@RequestParam("file") MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (isEmpty(originalFilename)) {
            return err("图片的文件名不可以为空");
        }
        Path basePath;
        if (!isBlankOrNull(pictureConfig.getPath())) {
            basePath = Paths.get(pictureConfig.getPath()).normalize().toAbsolutePath();
        } else {
            String userDir = System.getProperty("user.dir");
            if (isBlankOrNull(userDir)) {
                throw new IllegalStateException("System property 'user.dir' is not available");
            }
            basePath = Paths.get(userDir, "picture-path").normalize().toAbsolutePath();
        }
        if (!Files.isDirectory(basePath)) {
            try {
                Files.createDirectories(basePath);
            } catch (Exception e) {
                log.error("Failed to create the path", e);
                return err("路径创建失败");
            }
        }
        String tmpFilename = MD5Utils.encode(originalFilename) + randomAlphabetic(12) + ".tmp";
        String suffix = null;
        Path tmpFilePath = basePath.resolve(tmpFilename).normalize();
        if (!tmpFilePath.startsWith(basePath)) {
            return err("无效的文件路径");
        }
        try (InputStream in = file.getInputStream(); OutputStream out = Files.newOutputStream(tmpFilePath)) {
            byte[] buffer = new byte[4096];
            int bytesRead = in.read(buffer);
            if (bytesMatch(buffer, PNG)) {
                suffix = "png";
            } else if (bytesMatch(buffer, JPG)) {
                suffix = "jpg";
            } else if (bytesMatch(buffer, GIF)) {
                suffix = "gif";
            }
            if (bytesRead != -1 && suffix != null) {
                do {
                    out.write(buffer, 0, bytesRead);
                } while ((bytesRead = in.read(buffer)) != -1);
                out.flush();
            }
        } catch (Exception e) {
            log.error("Failed to save the file", e);
            return err("文件保存失败");
        }
        if (suffix == null) {
            try {
                Files.deleteIfExists(tmpFilePath);
            } catch (Exception e) {
                log.error("Failed to delete the file", e);
            }
            return err("不支持的图片类型");
        }
        String newFilename = tmpFilename.substring(0, tmpFilename.length() - 3) + suffix;
        Path newFilePath = basePath.resolve(newFilename).normalize();
        try {
            Files.move(tmpFilePath, newFilePath, StandardCopyOption.REPLACE_EXISTING);
        } catch (Exception e) {
            log.error("Failed to move the file", e);
            return err("文件移动失败");
        }
        return ok("/sdms-images/" + newFilename);
    }

    private static LayuiResult<Object> ok(String pictureURL) {
        Map<String, Object> map = new HashMap<>();
        map.put("pictureURL", pictureURL);
        return new LayuiResult<>(0, "success", 1L, Collections.singletonList(map));
    }

    private static LayuiResult<Object> err(String msg) {
        return new LayuiResult<>(1, msg, 0L, Collections.emptyList());
    }

    private static boolean bytesMatch(byte[] bytes, byte[] prefix) {
        if (bytes.length < prefix.length) {
            return false;
        }
        for (int i = 0; i < prefix.length; i++) {
            if (prefix[i] != bytes[i]) {
                return false;
            }
        }
        return true;
    }

}